{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import matplotlib\n",
    "matplotlib.use('nbagg')\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# mpl_toolkits"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In addition to the core library of Matplotlib, there are a few additional utilities that are set apart from Matplotlib proper for some reason or another, but are often shipped with Matplotlib.\n",
    "\n",
    "* [Basemap](http://matplotlib.org/basemap/) - shipped separately from matplotlib due to size of mapping data that are included.\n",
    "* [mplot3d](http://matplotlib.org/mpl_toolkits/mplot3d/index.html#toolkit-mplot3d-index) - shipped with matplotlib to provide very simple, rudimentary 3D plots in the same style as matplotlib's 2D plots.\n",
    "* [axes_grid1](http://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html) - An enhanced SubplotAxes. Very Enhanced..."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# mplot3d\n",
    "By taking advantage of Matplotlib's z-order layering engine, mplot3d emulates 3D plotting by projecting 3D data into 2D space, layer by layer. While it isn't going to replace any of the true 3D plotting libraries anytime soon, its goal is to allow for Matplotlib users to produce 3D plots with the same amount of simplicity as 2D plots."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from mpl_toolkits.mplot3d import Axes3D, axes3d\n",
    "\n",
    "fig, ax = plt.subplots(1, 1, subplot_kw={'projection': '3d'})\n",
    "X, Y, Z = axes3d.get_test_data(0.05)\n",
    "ax.plot_wireframe(X, Y, Z, rstride=10, cstride=10)\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# axes_grid1\n",
    "This module was originally intended as a collection of helper classes to ease the displaying of (possibly multiple) images with Matplotlib. Some of the functionality has come to be useful for non-image plotting as well. Some classes deals with the sizing and positioning of multiple Axes relative to each other ([`ImageGrid`](http://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html#imagegrid), [`RGB Axes`](http://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html#rgb-axes), and [`AxesDivider`](http://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html#axesdivider)). The [`ParasiteAxes`](http://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html#parasiteaxes) allow for the plotting of multiple datasets in the same axes, but with each their own x or y scale. Also, there is the [`AnchoredArtist`](http://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html#anchoredartists) that can be used to anchor particular artist objects in place.\n",
    "\n",
    "One can get a sense of the neat things that can be done with this toolkit by browsing through its user guide linked above. There is one particular feature that is an absolute must-have for me -- automatic allocation of space for colorbars."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from mpl_toolkits.axes_grid1 import AxesGrid\n",
    "fig = plt.figure()\n",
    "grid = AxesGrid(fig, 111, # similar to subplot(111)\n",
    "                nrows_ncols = (2, 2),\n",
    "                axes_pad = 0.2,\n",
    "                share_all=True,\n",
    "                label_mode = \"L\",  # similar to \"label_outer\"\n",
    "                cbar_location = \"right\",\n",
    "                cbar_mode=\"single\",\n",
    "               )\n",
    "\n",
    "extent = (-3,4,-4,3)\n",
    "for i in range(4):\n",
    "    im = grid[i].imshow(Z, extent=extent, interpolation=\"nearest\")\n",
    "    \n",
    "grid.cbar_axes[0].colorbar(im)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This next feature is commonly requested on the mailing lists.  The problem is that most people who request it don't quite know how to describe it.  We call it \"Parasite Axes\"."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# %load http://matplotlib.org/mpl_examples/axes_grid/demo_parasite_axes2.py\n",
    "\"\"\"\n",
    "Parasite axis demo\n",
    "\n",
    "The following code is an example of a parasite axis. It aims to show a user how\n",
    "to plot multiple different values onto one single plot. Notice how in this\n",
    "example, par1 and par2 are both calling twinx meaning both are tied directly to\n",
    "the x-axis. From there, each of those two axis can behave separately from the\n",
    "each other, meaning they can take on separate values from themselves as well as\n",
    "the x-axis.\n",
    "\"\"\"\n",
    "from mpl_toolkits.axes_grid1 import host_subplot\n",
    "import mpl_toolkits.axisartist as AA\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "host = host_subplot(111, axes_class=AA.Axes)\n",
    "plt.subplots_adjust(right=0.75)\n",
    "\n",
    "par1 = host.twinx()\n",
    "par2 = host.twinx()\n",
    "\n",
    "offset = 60\n",
    "new_fixed_axis = par2.get_grid_helper().new_fixed_axis\n",
    "par2.axis[\"right\"] = new_fixed_axis(loc=\"right\",\n",
    "                                    axes=par2,\n",
    "                                    offset=(offset, 0))\n",
    "\n",
    "par2.axis[\"right\"].toggle(all=True)\n",
    "\n",
    "host.set_xlim(0, 2)\n",
    "host.set_ylim(0, 2)\n",
    "\n",
    "host.set_xlabel(\"Distance\")\n",
    "host.set_ylabel(\"Density\")\n",
    "par1.set_ylabel(\"Temperature\")\n",
    "par2.set_ylabel(\"Velocity\")\n",
    "\n",
    "p1, = host.plot([0, 1, 2], [0, 1, 2], label=\"Density\")\n",
    "p2, = par1.plot([0, 1, 2], [0, 3, 2], label=\"Temperature\")\n",
    "p3, = par2.plot([0, 1, 2], [50, 30, 15], label=\"Velocity\")\n",
    "\n",
    "par1.set_ylim(0, 4)\n",
    "par2.set_ylim(1, 65)\n",
    "\n",
    "host.legend()\n",
    "\n",
    "host.axis[\"left\"].label.set_color(p1.get_color())\n",
    "par1.axis[\"right\"].label.set_color(p2.get_color())\n",
    "par2.axis[\"right\"].label.set_color(p3.get_color())\n",
    "\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And finally, as a nice teaser of what else axes_grid1 can do..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# %load http://matplotlib.org/mpl_toolkits/axes_grid/examples/demo_floating_axes.py\n",
    "\"\"\"\n",
    "Demo of the floating axes.\n",
    "\n",
    "This demo shows features of functions in floating_axes:\n",
    "    * Using scatter function and bar function with changing the\n",
    "      shape of the plot.\n",
    "    * Using GridHelperCurveLinear to rotate the plot and set the\n",
    "      boundary of the plot.\n",
    "    * Using FloatingSubplot to create a subplot using the return\n",
    "      value from GridHelperCurveLinear.\n",
    "    * Making sector plot by adding more features to GridHelperCurveLinear.\n",
    "\"\"\"\n",
    "from matplotlib.transforms import Affine2D\n",
    "import mpl_toolkits.axisartist.floating_axes as floating_axes\n",
    "import numpy as np\n",
    "import mpl_toolkits.axisartist.angle_helper as angle_helper\n",
    "from matplotlib.projections import PolarAxes\n",
    "from mpl_toolkits.axisartist.grid_finder import (FixedLocator, MaxNLocator,\n",
    "                                                 DictFormatter)\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "\n",
    "def setup_axes1(fig, rect):\n",
    "    \"\"\"\n",
    "    A simple one.\n",
    "    \"\"\"\n",
    "    tr = Affine2D().scale(2, 1).rotate_deg(30)\n",
    "\n",
    "    grid_helper = floating_axes.GridHelperCurveLinear(\n",
    "        tr, extremes=(-0.5, 3.5, 0, 4))\n",
    "\n",
    "    ax1 = floating_axes.FloatingSubplot(fig, rect, grid_helper=grid_helper)\n",
    "    fig.add_subplot(ax1)\n",
    "\n",
    "    aux_ax = ax1.get_aux_axes(tr)\n",
    "\n",
    "    grid_helper.grid_finder.grid_locator1._nbins = 4\n",
    "    grid_helper.grid_finder.grid_locator2._nbins = 4\n",
    "\n",
    "    return ax1, aux_ax\n",
    "\n",
    "\n",
    "def setup_axes2(fig, rect):\n",
    "    \"\"\"\n",
    "    With custom locator and formatter.\n",
    "    Note that the extreme values are swapped.\n",
    "    \"\"\"\n",
    "    tr = PolarAxes.PolarTransform()\n",
    "\n",
    "    pi = np.pi\n",
    "    angle_ticks = [(0, r\"$0$\"),\n",
    "                   (.25*pi, r\"$\\frac{1}{4}\\pi$\"),\n",
    "                   (.5*pi, r\"$\\frac{1}{2}\\pi$\")]\n",
    "    grid_locator1 = FixedLocator([v for v, s in angle_ticks])\n",
    "    tick_formatter1 = DictFormatter(dict(angle_ticks))\n",
    "\n",
    "    grid_locator2 = MaxNLocator(2)\n",
    "\n",
    "    grid_helper = floating_axes.GridHelperCurveLinear(\n",
    "        tr, extremes=(.5*pi, 0, 2, 1),\n",
    "        grid_locator1=grid_locator1,\n",
    "        grid_locator2=grid_locator2,\n",
    "        tick_formatter1=tick_formatter1,\n",
    "        tick_formatter2=None)\n",
    "\n",
    "    ax1 = floating_axes.FloatingSubplot(fig, rect, grid_helper=grid_helper)\n",
    "    fig.add_subplot(ax1)\n",
    "\n",
    "    # create a parasite axes whose transData in RA, cz\n",
    "    aux_ax = ax1.get_aux_axes(tr)\n",
    "\n",
    "    aux_ax.patch = ax1.patch  # for aux_ax to have a clip path as in ax\n",
    "    ax1.patch.zorder = 0.9  # but this has a side effect that the patch is\n",
    "    # drawn twice, and possibly over some other\n",
    "    # artists. So, we decrease the zorder a bit to\n",
    "    # prevent this.\n",
    "\n",
    "    return ax1, aux_ax\n",
    "\n",
    "\n",
    "def setup_axes3(fig, rect):\n",
    "    \"\"\"\n",
    "    Sometimes, things like axis_direction need to be adjusted.\n",
    "    \"\"\"\n",
    "\n",
    "    # rotate a bit for better orientation\n",
    "    tr_rotate = Affine2D().translate(-95, 0)\n",
    "\n",
    "    # scale degree to radians\n",
    "    tr_scale = Affine2D().scale(np.pi/180., 1.)\n",
    "\n",
    "    tr = tr_rotate + tr_scale + PolarAxes.PolarTransform()\n",
    "\n",
    "    grid_locator1 = angle_helper.LocatorHMS(4)\n",
    "    tick_formatter1 = angle_helper.FormatterHMS()\n",
    "\n",
    "    grid_locator2 = MaxNLocator(3)\n",
    "\n",
    "    ra0, ra1 = 8.*15, 14.*15\n",
    "    cz0, cz1 = 0, 14000\n",
    "    grid_helper = floating_axes.GridHelperCurveLinear(\n",
    "        tr, extremes=(ra0, ra1, cz0, cz1),\n",
    "        grid_locator1=grid_locator1,\n",
    "        grid_locator2=grid_locator2,\n",
    "        tick_formatter1=tick_formatter1,\n",
    "        tick_formatter2=None)\n",
    "\n",
    "    ax1 = floating_axes.FloatingSubplot(fig, rect, grid_helper=grid_helper)\n",
    "    fig.add_subplot(ax1)\n",
    "\n",
    "    # adjust axis\n",
    "    ax1.axis[\"left\"].set_axis_direction(\"bottom\")\n",
    "    ax1.axis[\"right\"].set_axis_direction(\"top\")\n",
    "\n",
    "    ax1.axis[\"bottom\"].set_visible(False)\n",
    "    ax1.axis[\"top\"].set_axis_direction(\"bottom\")\n",
    "    ax1.axis[\"top\"].toggle(ticklabels=True, label=True)\n",
    "    ax1.axis[\"top\"].major_ticklabels.set_axis_direction(\"top\")\n",
    "    ax1.axis[\"top\"].label.set_axis_direction(\"top\")\n",
    "\n",
    "    ax1.axis[\"left\"].label.set_text(r\"cz [km$^{-1}$]\")\n",
    "    ax1.axis[\"top\"].label.set_text(r\"$\\alpha_{1950}$\")\n",
    "\n",
    "    # create a parasite axes whose transData in RA, cz\n",
    "    aux_ax = ax1.get_aux_axes(tr)\n",
    "\n",
    "    aux_ax.patch = ax1.patch  # for aux_ax to have a clip path as in ax\n",
    "    ax1.patch.zorder = 0.9  # but this has a side effect that the patch is\n",
    "    # drawn twice, and possibly over some other\n",
    "    # artists. So, we decrease the zorder a bit to\n",
    "    # prevent this.\n",
    "\n",
    "    return ax1, aux_ax\n",
    "\n",
    "\n",
    "##########################################################\n",
    "fig = plt.figure(figsize=(8, 4))\n",
    "fig.subplots_adjust(wspace=0.3, left=0.05, right=0.95)\n",
    "\n",
    "ax1, aux_ax1 = setup_axes1(fig, 131)\n",
    "aux_ax1.bar([0, 1, 2, 3], [3, 2, 1, 3])\n",
    "\n",
    "ax2, aux_ax2 = setup_axes2(fig, 132)\n",
    "theta = np.random.rand(10)*.5*np.pi\n",
    "radius = np.random.rand(10) + 1.\n",
    "aux_ax2.scatter(theta, radius)\n",
    "\n",
    "ax3, aux_ax3 = setup_axes3(fig, 133)\n",
    "\n",
    "theta = (8 + np.random.rand(10)*(14 - 8))*15.  # in degrees\n",
    "radius = np.random.rand(10)*14000.\n",
    "aux_ax3.scatter(theta, radius)\n",
    "\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
